#ifndef FILEMANGER_H
#define FILEMANGER_H

/*!
 ***********************************************************************************
 * @File      : filemanager.h
 * @Brief     : 简要说明
 * @Details   : 详细说明
 * @Author    : BinWatson
 * @Date      : 2022-06-20 13:07:34
 * @Version   : v2.0
 * @Copyright : Copyright By BinWatson, All Rights Reserved
 ***********************************************************************************/

#include <QMap>
#include <QFile>
#include <QReadWriteLock>
#include "FileManager_global.h"
#include "Sington.h"

struct PrivateData;

class FILEMANGER_EXPORT FileManager : public QObject
{
    Q_OBJECT
private:
    FileManager();

public:

    ~FileManager();

    static FileManager* instance();

    /**
     * @brief   : 打开一个文件描述符，返回一个QFile*文件指针
     * @param   : url 以url的形式打开文件，详细参考QUrl文档
     * @param   : option 文件的操作模式，详细参考QIODevice::OpenModeFlag文档
     * @return  : QFile* 成功时返回一个指向打开文件的指针，失败时返回nullptr
     * @author  : BinWatson
     * @version : v1.0
     * @date    : 2022-05-28 09:51:15
     * @details : (1)该QFile*对象，存储在堆空间中，不能在外部进行delete操作否则会导致严重错误,
     *            用户不应该对QFile进行除读写关闭文件等基础操作外的任何操作，
     *            QFile*的内存管理，由FileManager来完成，用户不需要关心。
     *            (2)如果打开了相同的文件，那么就返回已打开文件的QFile*。
     */
    QSharedPointer<QFile> open(const QUrl &url, QIODevice::OpenModeFlag option = QIODevice::ReadWrite);
    QSharedPointer<QFile> openForRead(const QUrl &url);
    QSharedPointer<QFile> openForWrite(const QUrl &url);

    /**
     * @brief   : 打开一个文件描述符，返回一个QFile*文件指针
     * @param   : name 文件名(可是以相对路径，也可以是绝对路径)
     * @param   : option 文件的操作模式，详细参考QIODevice::OpenModeFlag文档
     * @return  : QFile* 成功时返回一个指向打开文件的指针，失败时返回nullptr
     * @author  : BinWatson
     * @version : v1.0
     * @date    : 2022-05-28 13:06:04
     * @details : 参考QFile* open(const QUrl &url, QIODevice::OpenModeFlag option = QIODevice::ReadWrite)
     */
    QSharedPointer<QFile> open(const QString &name, QIODevice::OpenModeFlag option = QIODevice::ReadWrite);
    QSharedPointer<QFile> openForRead(const QString &name);
    QSharedPointer<QFile> openForWrite(const QString &name);

    /**
     * @brief   : 根据文件名获取QFile*对象
     * @param   : name 文件名
     * @return  : QFile* 管理器中有这个文件
     *            nullptr 管理器中没有这个文件
     * @author  : BinWatson
     * @version : v1.0
     * @date    : 2022-05-28 13:01:38
     * @details : 详细看QFile* open(const QUrl &url, QIODevice::OpenModeFlag option = QIODevice::ReadWrite);
     *            的第(1)点
     */
    QSharedPointer<QFile> getFile(const QString &name);

    /**
     * @brief   : 添加一个QFile到FileManager，由FileManager负责在其关闭时进行释放。
     * @param   : file 一个动态申请QFile对象指针
     * @return  : true 添加成功
     *            false 出现了同名已经文件
     * @author  : BinWatson
     * @version : v1.0
     * @date    : 2022-05-28 15:09:34
     * @details : 给定的QFile*需要为new出来的对象，即存储在堆中的对象，不能使用&QFile的
     *            方式传入一个指针进来，否则或出现未定义行为。
     */
    Q_INVOKABLE void addFile(QSharedPointer<QFile> file);

    /**
     * @brief   : 设置文件接收的路径
     * @param   : path 路径
     * @return  : true 设置成功
     *            false 设置失败
     * @author  : BinWatson
     * @version : v1.0
     * @date    : 2022-06-21 20:09:29
     */
    bool setFileRecvPath(QString &path);
    QString fileRecvPath() const;

    Q_DISABLE_COPY_MOVE(FileManager);

private slots:
    void handleClose();

private:
    bool runInLoop() const;

private:
    friend Sington<FileManager>;

    PrivateData *m_config;
    mutable QReadWriteLock m_rwlock;     // used by m_files
    QMap<QString, QSharedPointer<QFile>> m_files;
};

#endif // FILEMANGER_H
